home *** CD-ROM | disk | FTP | other *** search
- /* * This file forms part of CorVu dbCGI * * CorVu dbCGI is Copyright (C) 1995 CorVu Pty Ltd. * Written by Troy Rollo * * CorVu dbCGI is free software. It may be modified and redistributed under * the terms of the CorVu General Public License, either version 1, or, at * your option, any later version. Ensure that you read this license before * modifying or redistributing the software. * * THIS PROGRAM IS PROVIDED "AS IS" WITH NO WORRANTY OF ANY KIND. YOU USE * THIS PROGRAM ENTIRELY AT YOUR OWN RISK. NEITHER CORVU, NOR ANY OTHER * PARTY MAY BE HELD RESPONSIBLE FOR ANY DAMAGES ARISING FROM YOUR USE OR * MISUSE OF THIS PROGRAM. */#include "dbcgi.h"#if defined(__sparc__) && defined(__sun__) && \ defined(__GNUC__) && defined(__svr4__) unsigned long long __cg92_used = 0x9de3bfa011000141ll;#endifFILE *fpOutput;dbw_connection *pconnList = 0;long nMaxBlob = 32768l;typedef struct{ char *pchCommand; void (*fcnHandler)(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);} dbw_commands;extern void DBInit(dbw_value *pval);extern void DBUnInit(dbw_value *pval);extern void DBConnect(dbw_value *pval);extern void DBDisconnect(dbw_value *pval);extern void DBQuery(dbw_value *pval);extern void DBExecute(dbw_value *pval);void DoDBInit(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);void DoDBUnInit(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);void DoDBConnect(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);void DoDBDisconnect(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);void DoDBQuery(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);void DoDBExecute(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);void DoFormat(dbw_buf pchBuffer, long ibytes, dbw_buf pchConnID);void DoHeadings(dbw_buf pchBuffer, long ibytes, dbw_buf pchConnID);void DoError(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);void DoValidateArgs(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);void DoValidateForm(dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID);dbw_buf ConvertFormat(dbw_buf pchSrc);void FormattedWrite(dbw_buf pchFormat);dbw_commands cmd_list[] ={ { "init", DoDBInit }, { "uninit", DoDBUnInit }, { "connect", DoDBConnect }, { "disconnect", DoDBDisconnect }, { "query", DoDBQuery }, { "execute", DoDBExecute }, { "format", DoFormat }, { "headings", DoHeadings }, { "error", DoError }, { "valarg", DoValidateArgs }, { "valform", DoValidateForm }};dbw_buf pchFormat = 0;dbw_buf pchError = 0;dbw_buf pchHeadings = 0;dbw_result *prsltCurrent = 0;int *piAreRepeats = 0;int iColsCurrent = 0;dbw_result *prsltPrevious = 0;int nColsPrevious = 0;dbw_buf pchSQLCurrent = 0;dbw_buf pchErrMsgCurrent = 0;long iErrNoCurrent = 0;char **ppchArgList;int nArgs;long iPid;long iSequence = 0;dbw_value *pvalForm = 0;char *pchValueCurrent = 0;int iEscaping = 0;int iInternal = 0;intMustEscape(char c){ return (!isalpha(c) && !isdigit(c));}static char achHexDigits[] = "0123456789abcdef";char *EscapedValue(char c){ static char achEscaped[4]; if (MustEscape(c)) { achEscaped[0] = '%'; achEscaped[1] = achHexDigits[(unsigned char) c / 16]; achEscaped[2] = achHexDigits[(unsigned char) c % 16]; achEscaped[3] = 0; } else { achEscaped[0] = c; achEscaped[1] = 0; } return achEscaped;}intHexToDec(char c){ if (c >= '0' && c <= '9') return c - '0'; if (c >= 'A' && c <= 'F') return c - 'A' + 10; if (c >= 'a' && c <= 'f') return c - 'a' + 10; return 0;}charGetNextEscape(char **ppchData){ char *pch = *ppchData; if (*pch == '%' && pch[1] && pch[2]) { *ppchData += 3; return HexToDec(pch[1]) * 16 + HexToDec(pch[2]); } else if (*pch == '+') { (*ppchData)++; return ' '; } else { (*ppchData)++; return *pch; }}voidShowError(char *pch){ fprintf(fpOutput, "%s: %s\r\n", pch, sys_errlist[errno]);}/* * Case insensitive comparison. Unlike strcmp & siblings, * this gives a boolean result. */intStringCompare( dbw_buf pch1, dbw_buf pch2, long iBytes){ while (iBytes--) { if (*pch1 != *pch2++) return 0; if (!*pch1++) return 1; } return 1;}/* String compare that uses dbw_buf types */longStringLength(dbw_buf pchStr){ long iLength = 0; while (*pchStr++) iLength++; return iLength;}voidStringCopy(dbw_buf pchDest, dbw_buf pchSrc){ while ((*pchDest++ = *pchSrc++) != 0);}dbw_bufStringDuplicate(dbw_buf pchSource){ dbw_buf pchDest = new2(char, StringLength(pchSource) + 1); StringCopy(pchDest, pchSource); return pchDest;}/* * Search for commands in the buffer and act on them */voidProcessBuffer( dbw_buf pchBuffer, long iBytes, int iTop){ dbw_buf pchNow, pchCommand, pchConnection; long iLoc = 0; int nWritten; int nWrite; int i; while (iBytes) { iLoc = 0; pchNow = pchBuffer; while (iLoc < iBytes - 5 && (*pchNow != '<' || !StringCompare(pchNow, "<sql ", 5))) { iLoc++; pchNow++; } if (iLoc >= iBytes - 5) { pchNow += iBytes - iLoc; iLoc = iBytes; } if (iLoc > 0) { iBytes -= iLoc; *pchNow = 0; FormattedWrite(pchBuffer); pchBuffer = pchNow; } if (iBytes > 0) { pchCommand = pchBuffer + 5; iBytes -= 5; iLoc = 0; for (pchBuffer = pchCommand; iLoc != iBytes && *pchBuffer != '>'; pchBuffer++, iLoc++); if (iLoc == iBytes) return; *pchBuffer++ = '\0'; iBytes -= iLoc + 1; for (pchConnection = pchCommand; *pchConnection && *pchConnection != ' '; pchConnection++); if (*pchConnection) *pchConnection++ = '\0'; iLoc = 0; pchNow = pchBuffer; while (iLoc < iBytes - 6 && (*pchNow != '<' || !StringCompare(pchNow, "</sql>", 6))) { iLoc++; pchNow++; } if (iLoc >= iBytes - 6) { pchNow += iBytes - iLoc; iLoc = iBytes; } else { *pchNow = 0; } for (i = 0; i < rangeof(cmd_list); i++) { if (StringCompare(cmd_list[i].pchCommand, pchCommand, StringLength(pchCommand) + 1)) { (*cmd_list[i].fcnHandler)(pchBuffer, iLoc, pchConnection); break; } } if (iLoc + 6 >= iBytes) { iBytes = 0; pchBuffer = pchNow; } else { iBytes -= iLoc + 6; pchBuffer = pchNow + 6; } } } return;}/* * Read a file in, and let the games begin. * We read the file into memory in its entirity because we * expect that it will be a reasonable size to do so, and * because that simplifies processing. */voidReadFile(char *pchFileName){ struct stat sbuf; dbw_buf pchBuffer, pchNow; FILE *fp; long iBytes; int iRead; if (stat(pchFileName, &sbuf) == -1) { ShowError(pchFileName); return; } fp = fopen(pchFileName, "r"); pchBuffer = new2(char, sbuf.st_size + 1); if (!pchBuffer) { fprintf(fpOutput, "<TITLE>Error reading %s</TITLE>\r\nUnable to allocate %ld bytes\n", pchFileName, sbuf.st_size); return; } pchNow = pchBuffer; iBytes = 0; while ((iRead = ((sbuf.st_size - iBytes > READ_SIZE) ? READ_SIZE : ((int) (sbuf.st_size - iBytes)))) && (iRead = fread(pchNow, 1, iRead, fp)) > 0) { iBytes += iRead; pchNow += iRead; } fclose(fp); if (!iBytes) { fprintf(fpOutput, "<TITLE>Error reading %s</TITLE>\r\nEmpty file\n", pchFileName); free(pchBuffer); return; } pchBuffer[iBytes] = 0; ProcessBuffer(pchBuffer, iBytes, 1); free(pchBuffer); return;}dbw_value *GetKeys( dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID){ dbw_value *pvalList = 0, *pvalNew; dbw_buf pchNow, pchValue, pchEqual; long iNow; if (pchConnID && *pchConnID) { pvalNew = new(dbw_value); pvalNew->pchKey = "ConnID"; pvalNew->pchValue = pchConnID; pvalNew->pvalNext = pvalList; pvalList = pvalNew; } while (iBytes) { for (pchNow = pchBuffer, iNow = 0; *pchNow != '\n' && iNow < iBytes; pchNow++, iNow++); if (iNow < iBytes) *pchNow++ = '\0'; if (!*pchBuffer) { pchBuffer++; iBytes--; continue; } for (pchEqual = pchBuffer; *pchEqual && *pchEqual != '='; pchEqual++); if (*pchEqual) { *pchEqual++ = 0; pvalNew = new(dbw_value); pvalNew->pchKey = pchBuffer; pvalNew->pchValue = pchEqual; pvalNew->pvalNext = pvalList; pvalList = pvalNew; } iBytes -= iNow; pchBuffer = pchNow; } return pvalList;}dbw_value *GetNamedKey( dbw_buf pchBuffer, long iBytes, dbw_buf pchKey, dbw_buf pchConnID){ dbw_value *pvalList = 0, *pvalNew; if (pchConnID && *pchConnID) { pvalNew = new(dbw_value); pvalNew->pchKey = "ConnID"; pvalNew->pchValue = pchConnID; pvalNew->pvalNext = pvalList; pvalList = pvalNew; } if (pchBuffer && *pchBuffer) { pvalNew = new(dbw_value); pvalNew->pchKey = pchKey; pvalNew->pchValue = pchBuffer; pvalNew->pvalNext = pvalList; pvalList = pvalNew; } return pvalList;}voidFreeKeys(dbw_value *pvalList){ dbw_value *pvalNext; while (pvalList) { pvalNext = pvalList->pvalNext; free(pvalList); pvalList = pvalNext; }}voidDoDBInit( dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID){ dbw_buf pchBuf = ConvertFormat(pchBuffer); dbw_value *pvalList = GetKeys(pchBuf, iBytes, pchConnID); char *pchMaxBlob = GetValue(pvalList, "MAXBLOB"); if (pchMaxBlob) nMaxBlob = atoi(pchMaxBlob); else nMaxBlob = 32768l; DBInit(pvalList); FreeKeys(pvalList); free(pchBuf);}voidDoDBUnInit( dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID){ dbw_buf pchBuf = ConvertFormat(pchBuffer); dbw_value *pvalList = GetKeys(pchBuf, iBytes, pchConnID); DBUnInit(pvalList); FreeKeys(pvalList); free(pchBuf);}voidDoDBConnect( dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID){ dbw_buf pchBuf = ConvertFormat(pchBuffer); dbw_value *pvalList = GetKeys(pchBuf, iBytes, pchConnID); DBConnect(pvalList); FreeKeys(pvalList); free(pchBuf);}voidDoDBDisconnect( dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID){ dbw_buf pchBuf = ConvertFormat(pchBuffer); dbw_value *pvalList = GetKeys(pchBuf, iBytes, pchConnID); DBDisconnect(pvalList); FreeKeys(pvalList); free(pchBuf);}voidDoDBQuery( dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID){ int i; dbw_buf pchBuf = ConvertFormat(pchBuffer); dbw_value *pvalList = GetNamedKey(pchBuf, iBytes, "Query", pchConnID); DBQuery(pvalList); FreeKeys(pvalList); free(pchBuf); if (prsltPrevious) { for (i = 0; i < nColsPrevious; i++) if (prsltPrevious[i].pchCharValue) free(prsltPrevious[i].pchCharValue); free(prsltPrevious); prsltPrevious = 0; } if (piAreRepeats) { free(piAreRepeats); piAreRepeats = 0; }}voidDoDBExecute( dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID){ dbw_buf pchBuf = ConvertFormat(pchBuffer); dbw_value *pvalList = GetNamedKey(pchBuf, iBytes, "Query", pchConnID); DBExecute(pvalList); FreeKeys(pvalList); free(pchBuf);}voidDoFormat( dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID){ pchFormat = pchBuffer;}voidDoHeadings( dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID){ pchHeadings = pchBuffer;}voidDoError( dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID){ pchError = pchBuffer;}char NextCChar(char **cPtr){ char c; c = *(*cPtr)++; if (c == '\\' && **cPtr) { c = *(*cPtr)++; if (c == '\\') c = '\\'; else if (c == 'n') c = '\n'; else if (c == 'r') c = '\r'; else if (c == 'b') c = '\b'; else if (c == 't') c = '\t'; else if (c >= '0' && c <= '7') { int i; i = (c - '0'); c = **cPtr; if (c >= '0' && c <= '7') { (*cPtr)++; i *= 8; i += c - '0'; c = **cPtr; if (c >= '0' && c <= '7') { i *= 8; (*cPtr)++; i += c - '0'; } } c = (char) i; } } return c;}voidFailValidate( dbw_value *pvalRules, char *pchValue, char *pchFormat){ char *pchForm2 = GetValue(pvalRules, "FORMAT"); if (pchForm2) pchFormat = pchForm2; pchValueCurrent = pchValue; FormattedWrite(pchFormat); exit(0);} voidValidateValue( char *pchValue, dbw_value *pvalRules, char *pchItem, char *pchFormat){ char *pchTemp; char *c, *c2; char cNow; pchTemp = GetValue(pvalRules, "CLASS"); if (pchTemp) { c = pchValue; if (!strcmp(pchTemp, "NUMERIC")) { if (*c == '-' || *c == '+') c++; while (*c && isdigit(*c)) c++; if (*c == '.') c++; while (*c && isdigit(*c)) c++; if (*c) FailValidate(pvalRules, pchValue, pchFormat); } else if (!strcmp(pchTemp, "PLAINTEXT")) { while (*c) { if (*c < ' ' || *c >= '\177') FailValidate(pvalRules, pchValue, pchFormat); c++; } } else if (!strcmp(pchTemp, "TABBEDTEXT")) { while (*c) { if ((*c < ' ' && *c != '\t') || *c >= '\177') FailValidate(pvalRules, pchValue, pchFormat); c++; } } FreeString(pchTemp); } pchTemp = GetValue(pvalRules, "MAXCHARS"); if (pchTemp) { if (strlen(pchValue) > atoi(pchTemp)) FailValidate(pvalRules, pchValue, pchFormat); FreeString(pchTemp); } pchTemp = GetValue(pvalRules, "MINCHARS"); if (pchTemp) { if (strlen(pchValue) < atoi(pchTemp)) FailValidate(pvalRules, pchValue, pchFormat); FreeString(pchTemp); } pchTemp = GetValue(pvalRules, "FORBIDDEN"); if (pchTemp) { c = pchValue; c2 = pchTemp; while (*c2) { cNow = NextCChar(&c2); if (strchr(c, cNow)) FailValidate(pvalRules, pchValue, pchFormat); } FreeString(pchTemp); } pchTemp = GetValue(pvalRules, "RANGE"); if (pchTemp) { c = pchValue; while (*c) { int iIsOK = 0; c2 = pchTemp; while (*c2) { cNow = NextCChar(&c2); if (cNow == *c) { iIsOK = 1; break; } } if (!iIsOK) FailValidate(pvalRules, pchValue, pchFormat); c++; } FreeString(pchTemp); }}voidDoValidateArgs( dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID){ dbw_value *pvalList = GetKeys(pchBuffer, iBytes, pchConnID); char *pchTest = GetValue(pvalList, "ConnID"); int iArg; if (pchTest) { iArg = atoi(pchTest); if (iArg >= 1 && iArg <= nArgs) ValidateValue(ppchArgList[iArg - 1], pvalList, pchTest, "<H1>Error</H1>" "The argument value of %v is invalid<BR>"); } iArg = atoi(pchTest); FreeString(pchTest); FreeKeys(pvalList);}voidDoValidateForm( dbw_buf pchBuffer, long iBytes, dbw_buf pchConnID){ dbw_value *pvalList = GetKeys(pchBuffer, iBytes, pchConnID); char *pchTest = GetValue(pvalList, "ConnID"); if (pchTest) { char *pchValue = GetValue(pvalForm, pchTest); if (pchValue) ValidateValue(pchValue, pvalList, pchTest, "<H1>Error</H1>" "The form value of %v is invalid<BR>"); } FreeString(pchTest); FreeKeys(pvalList);}typedef struct __dbw_formdata{ void (*func)(void *pvDest, char *pchText, int iBytes); void *pvDest;} dbw_formdata;typedef struct{ int iBytes; int iLen; char *pchData;} dbw_string;voidDataToOutput(void *pvDest, char *pchText, int iBytes){ FILE *fp = (FILE *) pvDest; fwrite(pchText, 1, iBytes, fp);}voidDataToString(void *pvDest, char *pchText, int iBytes){ dbw_string *pstr = (dbw_string *) pvDest; if (iBytes + pstr->iLen >= pstr->iBytes) { char *pchNew; int iNew; int iMod; iNew = pstr->iLen + iBytes + 1; iMod = iNew % 256; if (iMod) iNew += 256 - iMod; pchNew = new2(char, iNew); if (pstr->pchData) { memcpy(pchNew, pstr->pchData, pstr->iLen); free(pstr->pchData); } pstr->pchData = pchNew; pstr->iBytes = iNew; } memcpy(pstr->pchData + pstr->iLen, pchText, iBytes); pstr->iLen += iBytes; pstr->pchData[pstr->iLen] = 0;}voidEscapedDataToOutput(void *pvDest, char *pchText, int iBytes){ int i = 0; dbw_formdata *pfdata = (dbw_formdata *) pvDest; char achData[4]; while (i < iBytes) { if (MustEscape(pchText[i])) { if (i) { (*pfdata->func)(pfdata->pvDest, pchText, i); iBytes -= i; pchText += i; } strcpy(achData, EscapedValue(pchText[0])); (*pfdata->func)(pfdata->pvDest, achData, 3); pchText++; iBytes--; i = 0; } else { i++; } } if (iBytes) (*pfdata->func)(pfdata->pvDest, pchText, iBytes);}voidDoubleUpSQuotes(void *pvDest, char *pchText, int iBytes){ int i = 0; dbw_formdata *pfdata = (dbw_formdata *) pvDest; char achData[4]; while (i < iBytes) { if (pchText[i] == '\'') { if (i) { (*pfdata->func)(pfdata->pvDest, pchText, i); iBytes -= i; pchText += i; } strcpy(achData, EscapedValue(pchText[0])); (*pfdata->func)(pfdata->pvDest, "''", 2); pchText++; iBytes--; i = 0; } else { i++; } } if (iBytes) (*pfdata->func)(pfdata->pvDest, pchText, iBytes);}voidDoubleUpDQuotes(void *pvDest, char *pchText, int iBytes){ int i = 0; dbw_formdata *pfdata = (dbw_formdata *) pvDest; char achData[4]; while (i < iBytes) { if (pchText[i] == '"') { if (i) { (*pfdata->func)(pfdata->pvDest, pchText, i); iBytes -= i; pchText += i; } strcpy(achData, EscapedValue(pchText[0])); (*pfdata->func)(pfdata->pvDest, "\"\"", 2); pchText++; iBytes--; i = 0; } else { i++; } } if (iBytes) (*pfdata->func)(pfdata->pvDest, pchText, iBytes);}voidDoubleUpBackSlashes(void *pvDest, char *pchText, int iBytes){ int i = 0; dbw_formdata *pfdata = (dbw_formdata *) pvDest; char achData[4]; while (i < iBytes) { if (pchText[i] == '\\') { if (i) { (*pfdata->func)(pfdata->pvDest, pchText, i); iBytes -= i; pchText += i; } strcpy(achData, EscapedValue(pchText[0])); (*pfdata->func)(pfdata->pvDest, "\\\\", 2); pchText++; iBytes--; i = 0; } else { i++; } } if (iBytes) (*pfdata->func)(pfdata->pvDest, pchText, iBytes);}voidPadSpaces(dbw_formdata *pfdata, int iSpaces){ while (iSpaces > 0) { (*pfdata->func)(pfdata->pvDest, " ", iSpaces > 20 ? 20 : iSpaces); iSpaces -= 20; }}voidFormatChar(dbw_formdata *pfdata, char *pchData, int iWidth, int iPrec){ int iLen = strlen(pchData); int iNow = 0; if (iPrec > 0 && iLen > iPrec) iLen = iPrec; iPrec = iLen; /* If we are inside an HTML escaping expansion, or * we are converting values for internal use by dbCGI, * don't convert line breaks or HTML special characters. */ if (iEscaping || iInternal) iNow = iPrec; while (iNow < iPrec) { if (pchData[iNow] == '\r' || pchData[iNow] == '\n') { if (iNow) (*pfdata->func)(pfdata->pvDest, pchData, iNow); pchData += iNow; iPrec -= iNow; iNow = 0; (*pfdata->func)(pfdata->pvDest, "<BR>\r\n", 6); if (pchData[0] == '\r' && iPrec > 1 && pchData[1] == '\n') { pchData += 2; iPrec -= 2; } else { pchData++; iPrec--; } } else if (pchData[iNow] == '<' || pchData[iNow] == '>' || pchData[iNow] == '&' || pchData[iNow] == '"') { if (iNow) (*pfdata->func)(pfdata->pvDest, pchData, iNow); if (pchData[iNow] == '<') (*pfdata->func)(pfdata->pvDest, "<", 4); else if (pchData[iNow] == '>') (*pfdata->func)(pfdata->pvDest, ">", 4); else if (pchData[iNow] == '"') (*pfdata->func)(pfdata->pvDest, """, 6); else if (pchData[iNow] == '&') (*pfdata->func)(pfdata->pvDest, "&", 5); pchData += iNow + 1; iPrec -= iNow + 1; iNow = 0; } else { iNow++; } } if (iPrec) (*pfdata->func)(pfdata->pvDest, pchData, iPrec); if (iWidth > iLen) PadSpaces(pfdata, iWidth - iLen);}voidFormatFloat(dbw_formdata *pfdata, double fValue, int iWidth, int iPrec){ static char achFloatBuf[1024]; sprintf(achFloatBuf, "%*.*f", iWidth, iPrec, fValue); (*pfdata->func)(pfdata->pvDest, achFloatBuf, strlen(achFloatBuf));}voidFormatInteger(dbw_formdata *pfdata, long iValue, int iWidth, int iPrec){ long iModulus = 1; long iFraction; int i = iPrec; int iCharacters; char achBuffer[50]; long iAbsValue; if (iPrec > 20) return; while (i--) iModulus *= 10; if (iValue < 0) iAbsValue = -iValue; else iAbsValue = iValue; if (iModulus != 1) { iFraction = iAbsValue % iModulus; iAbsValue = (iAbsValue - iFraction) / iModulus; if (iValue < 0) iValue = -iAbsValue; else iValue = iAbsValue; } else { iFraction = 0; } iModulus = 10; i = 1; while (iModulus <= iValue && iModulus > 0) { i++; iModulus *= 10; } if (iValue < 0) i++; iCharacters = i + iPrec + (iPrec ? 1 : 0); if (iCharacters < iWidth) PadSpaces(pfdata, iWidth - iCharacters); sprintf(achBuffer, "%ld", iValue); (*pfdata->func)(pfdata->pvDest, achBuffer, i); if (iPrec) { (*pfdata->func)(pfdata->pvDest, ".", 1); memset(achBuffer, '0', sizeof(achBuffer)); sprintf(achBuffer + iPrec, "%ld", iFraction); (*pfdata->func)(pfdata->pvDest, achBuffer + strlen(achBuffer + iPrec), iPrec); }}voidFormatResult(dbw_formdata *pfdata, int iWidth, int iPrec, int iIndex){ if (iIndex < 1 || !prsltCurrent || iColsCurrent < iIndex) return; iIndex--; if (prsltCurrent[iIndex].iIsNull) { PadSpaces(pfdata, iWidth); return; } switch(prsltCurrent[iIndex].type) { case DBWT_Char: FormatChar(pfdata, prsltCurrent[iIndex].pchCharValue, iWidth, iPrec); break; case DBWT_Int: FormatInteger(pfdata, prsltCurrent[iIndex].iIntValue, iWidth, 0); break; case DBWT_Dec: FormatInteger(pfdata, prsltCurrent[iIndex].iIntValue, iWidth, prsltCurrent[iIndex].iScale); break; case DBWT_Float: FormatFloat(pfdata, prsltCurrent[iIndex].fValue, iWidth, iPrec == -1 ? prsltCurrent[iIndex].iScale : iPrec); break; }}voidFormatHeading(dbw_formdata *pfdata, int iWidth, int iPrec, int iIndex){ if (iIndex < 1 || !prsltCurrent || iColsCurrent < iIndex) return; FormatChar(pfdata, prsltCurrent[iIndex - 1].pchHeading, iWidth, iPrec);}voidFormatArg(dbw_formdata *pfdata, int iWidth, int iPrec, int iIndex){ if (iIndex < 1 || iIndex > nArgs) return; FormatChar(pfdata, ppchArgList[iIndex - 1], iWidth, iPrec);}char *FindMatch( char *pchStart, char *pchBounds, char *pchChars){ int nOpen = 1; if (*pchStart != pchChars[0]) return 0; while (++pchStart + 1 < pchBounds) { if (*pchStart == '%') { if (pchStart[1] == pchChars[0]) { nOpen++; pchStart++; } else if (pchStart[1] == pchChars[1]) { if (!--nOpen) return pchStart; pchStart++; } else if (isdigit(pchStart[1])) { while (++pchStart + 1 < pchBounds && isdigit(pchStart[1])); if (pchStart < pchBounds && *pchStart == pchChars[0]) nOpen++; } else { ++pchStart; } } } return 0;}void DoConditionalBounded(dbw_buf pchFormat, dbw_formdata *pfdata, char *pchBoundary);void DoFile(dbw_buf pchFormat, char *pchBoundary, int iIndex);void DoCommand(dbw_buf pchFormat, char *pchBoundary);void DoFormVar(char *pchVarName, dbw_formdata *pfdata, char *pchBoundary, char cType);void SetFormVar(char *pchVarName, char *pchBoundary);voidDoFormattingBounded(dbw_buf pchFormat, dbw_formdata *pfdata, char *pchBoundary){ char *pchNow; int iWidth; int iPrec; int iIndex; int iNum; int iStage; char *pchRemote; if (!pchFormat) return; for (pchNow = pchFormat; pchNow != pchBoundary; pchNow++) { if (*pchNow == '%') { if (pchNow != pchFormat) { (*pfdata->func)(pfdata->pvDest, pchFormat, pchNow - pchFormat); pchFormat = pchNow; } pchNow++; if (pchNow == pchBoundary) break; iWidth = 0; iPrec = -1; iIndex = -1; if (*pchNow == '.') { pchNow++; iStage = 1; } else { iStage = 0; } while (pchNow != pchBoundary && isdigit(*pchNow)) { iNum = 0; while (pchNow != pchBoundary && isdigit(*pchNow)) { iNum *= 10; iNum += *pchNow - '0'; pchNow++; } if (pchNow == pchBoundary) break; if ((*pchNow == '.' || *pchNow == ':') && iStage == 0) { iWidth = iNum; iStage = 1; pchNow++; } else if (*pchNow == ':' && iStage == 1) { iPrec = iNum; iStage = 2; pchNow++; } else if (*pchNow && iStage < 3) { iIndex = iNum; iStage = 3; } } if (pchNow == pchBoundary) break; switch (*pchNow) { case '%': (*pfdata->func)(pfdata->pvDest, "%", 1); break; case '$': FormatInteger(pfdata, iPid, iWidth, 0); break; case '#': FormatInteger(pfdata, iSequence, iWidth, 0); case 'd': FormatResult(pfdata, iWidth, iPrec, iIndex); break; case 'h': FormatHeading(pfdata, iWidth, iPrec, iIndex); break; case 'a': FormatArg(pfdata, iWidth, iPrec, iIndex); break; case 'e': if (pchErrMsgCurrent) FormatChar(pfdata, pchErrMsgCurrent, iWidth, iPrec); break; case 'c': if (pchSQLCurrent) FormatChar(pfdata, pchSQLCurrent, iWidth, iPrec); break; case 'n': FormatInteger(pfdata, iErrNoCurrent, iWidth, 0); break; case 'v': if (pchValueCurrent) FormatChar(pfdata, pchValueCurrent, iWidth, iPrec); break; case '{': pchRemote = FindMatch(pchNow, pchBoundary, "{}"); if (pchRemote) { dbw_formdata fdata; int iOld; iOld = iEscaping; iEscaping = 1; fdata.func = EscapedDataToOutput; fdata.pvDest = pfdata; DoFormattingBounded(pchNow + 1, &fdata, pchRemote); iEscaping = iOld; pchNow = pchRemote + 1; } break; case '(': if (iIndex < 1 || !prsltCurrent || iColsCurrent < iIndex || !(pchRemote = FindMatch(pchNow, pchBoundary, "()"))) break; if (!prsltCurrent[iIndex - 1].iIsNull) DoFormattingBounded(pchNow + 1, pfdata, pchRemote); pchNow = pchRemote + 1; break; case '[': pchRemote = FindMatch(pchNow, pchBoundary, "[]"); pchNow++; if (pchNow >= pchBoundary) break; if (pchRemote <= pchNow || !pchRemote) break; switch (*pchNow) { case '!': DoConditionalBounded(pchNow + 1, pfdata, pchRemote); break; case '@': DoFile(pchNow + 1, pchRemote, iIndex); break; case '|': DoCommand(pchNow + 1, pchRemote); break; case '"': case '\'': case '\\': { dbw_formdata fdata; if (*pchNow == '\'') fdata.func = DoubleUpSQuotes; else if (*pchNow == '"') fdata.func = DoubleUpDQuotes; else if (*pchNow == '\\') fdata.func = DoubleUpBackSlashes; fdata.pvDest = pfdata; DoFormattingBounded(pchNow + 1, &fdata, pchRemote); pchNow = pchRemote + 1; } break; case '-': { int iOld; iOld = iInternal; iInternal = 0; DoFormattingBounded(pchNow + 1, pfdata, pchRemote); pchNow = pchRemote + 1; iInternal = iOld; } break; case '=': /* Sub value */ case '~': /* Sub if no value */ case '?': /* Sub if has value */ DoFormVar(pchNow + 1, pfdata, pchRemote, *pchNow); pchNow = pchRemote + 1; break; case '*': /* Set variable */ SetFormVar(pchNow + 1, pchRemote); pchNow = pchRemote + 1; break; } pchNow = pchRemote + 1; break; } pchFormat = pchNow + 1; } } if (pchFormat != pchNow) (*pfdata->func)(pfdata->pvDest, pchFormat, pchNow - pchFormat);}/* The inclusion of "Char" in DBW_IS_BINARY is for the benefit * of databases which do not have binary datatypes. They can store * binary data as hexadecimal or uuencoded character fields, * use the "%n[@file%]" feature to save this to a file, then use * the "%[|command%]" feature to convert it to binary */#define DBW_IS_BINARY(x) ((x) == DBWT_Raw || \ (x) == DBWT_Raw_Sidx || \ (x) == DBWT_Raw_Lidx || \ (x) == DBWT_Char)voidDoFile(dbw_buf pchFormat, char *pchBoundary, int iIndex){ dbw_formdata fdata; dbw_string str; FILE *fp; if (!prsltCurrent || iIndex < 1 || iIndex > iColsCurrent || !DBW_IS_BINARY(prsltCurrent[iIndex - 1].type) || pchBoundary <= pchFormat) return; str.iBytes = 256; str.iLen = 0; str.pchData = new2(char, 256); str.pchData[0] = 0; fdata.func = DataToString; fdata.pvDest = &str; DoFormattingBounded(pchFormat, &fdata, pchBoundary); fp = fopen(str.pchData,#ifdef _Windows "wb");#else "w");#endif if (fp) { switch(prsltCurrent[iIndex - 1].type) { case DBWT_Raw: fwrite(prsltCurrent[iIndex - 1].pchCharValue, 1, prsltCurrent[iIndex - 1].iScale, fp); break; case DBWT_Raw_Sidx: fwrite(prsltCurrent[iIndex - 1].pchCharValue + sizeof(short), 1, *(unsigned short *) prsltCurrent[iIndex - 1].pchCharValue, fp); break; case DBWT_Raw_Lidx: fwrite(prsltCurrent[iIndex - 1].pchCharValue + sizeof(long), 1, *(unsigned long *) prsltCurrent[iIndex - 1].pchCharValue, fp); break; case DBWT_Char: fwrite(prsltCurrent[iIndex - 1].pchCharValue, 1, strlen(prsltCurrent[iIndex - 1].pchCharValue), fp); } fclose(fp); } free(str.pchData);}voidDoCommand(dbw_buf pchFormat, char *pchBoundary){#ifndef _Windows dbw_formdata fdata; dbw_string str; if (pchBoundary <= pchFormat) return; str.iBytes = 256; str.iLen = 0; str.pchData = new2(char, 256); str.pchData[0] = 0; fdata.func = DataToString; fdata.pvDest = &str; DoFormattingBounded(pchFormat, &fdata, pchBoundary); system(str.pchData); free(str.pchData);#endif}voidDoConditionalBounded(dbw_buf pchFormat, dbw_formdata *pfdata, char *pchBoundary){ int iNum; int iGo = 0; while (pchFormat != pchBoundary && *pchFormat != ':') { if (!isdigit(*pchFormat)) return; iNum = 0; while (pchFormat != pchBoundary && isdigit(*pchFormat)) { iNum *= 10; iNum += *pchFormat - '0'; pchFormat++; } if (pchFormat == pchBoundary || (*pchFormat != ':' && *pchFormat != ',')) return; if (iNum < 1 || iNum > iColsCurrent) return; if (!prsltPrevious || !piAreRepeats[iNum - 1]) iGo = 1; if (*pchFormat == ',') pchFormat++; } if (pchFormat >= pchBoundary) return; pchFormat++; if (!iGo) return; DoFormattingBounded(pchFormat, pfdata, pchBoundary);}voidSetFormVar(char *pchVarName, char *pchBoundary){ char *pchVarEnd; dbw_formdata fdata; dbw_string str; dbw_value *pval; for (pchVarEnd = pchVarName; pchVarEnd != pchBoundary && *pchVarEnd != ':'; pchVarEnd++); if (pchVarEnd == pchBoundary) return; str.iBytes = 256; str.iLen = 0; str.pchData = new2(char, 256); str.pchData[0] = 0; fdata.func = DataToString; fdata.pvDest = &str; *pchVarEnd++ = 0; DoFormattingBounded(pchVarEnd, &fdata, pchBoundary); pval = new(dbw_value); pval->pchKey = StringDuplicate(pchVarName); pval->pchValue = str.pchData; pval->pvalNext = pvalForm; pvalForm = pval;}voidDoFormVar(char *pchVarName, dbw_formdata *pfdata, char *pchBoundary, char cType){ int iNum; char *pchColon; char *pchVarCopy; char *pchValue; for (pchColon = pchVarName; pchColon != pchBoundary && *pchColon != ':'; pchColon++); if (cType != '=' && pchColon == pchBoundary) return; pchVarCopy = new2(char, (pchColon - pchVarName) + 1); memcpy(pchVarCopy, pchVarName, pchColon - pchVarName); pchVarCopy[pchColon - pchVarName] = 0; pchValue = GetValue(pvalForm, pchVarCopy); free(pchVarCopy); if (pchValue) { switch(cType) { case '=': FormatChar(pfdata, pchValue, 0, -1); break; case '?': DoFormattingBounded(pchColon + 1, pfdata, pchBoundary); break; } } else { switch(cType) { case '=': if (pchColon == pchBoundary) break; case '~': DoFormattingBounded(pchColon + 1, pfdata, pchBoundary); break; } } FreeString(pchValue);}voidDoFormatting(dbw_buf pchFormat, dbw_formdata *pfdata){ if (!pchFormat) return; DoFormattingBounded(pchFormat, pfdata, pchFormat + StringLength(pchFormat));}voidFormattedWrite(dbw_buf pchFormat){ dbw_formdata fdata; fdata.func = DataToOutput; fdata.pvDest = fpOutput; DoFormatting(pchFormat, &fdata);}dbw_bufConvertFormat(dbw_buf pchFormat){ dbw_formdata fdata; dbw_string str; str.iBytes = 256; str.iLen = 0; str.pchData = new2(char, 256); str.pchData[0] = 0; fdata.func = DataToString; fdata.pvDest = &str; iInternal = 1; DoFormatting(pchFormat, &fdata); iInternal = 0; return str.pchData;}voidFormatOutput( dbw_result *prslt, int iColumns){ int i; prsltCurrent = prslt; iColsCurrent = iColumns; if (prsltPrevious) { if (!piAreRepeats) piAreRepeats = new2(int, iColumns); for (i = 0; i < iColumns; i++) { if (prslt[i].iIsNull || prsltPrevious[i].iIsNull) { piAreRepeats[i] = (prslt[i].iIsNull && prsltPrevious[i].iIsNull); continue; } switch(prslt[i].type) { case DBWT_Char: piAreRepeats[i] = !strcmp(prslt[i].pchCharValue, prsltPrevious[i].pchCharValue); break; case DBWT_Float: piAreRepeats[i] = (prslt[i].fValue == prsltPrevious[i].fValue); break; case DBWT_Int: piAreRepeats[i] = (prslt[i].iIntValue == prsltPrevious[i].iIntValue); break; default: piAreRepeats[i] = 0; break; } } } FormattedWrite(pchFormat); prsltCurrent = 0; iColsCurrent = 0; if (!prsltPrevious) { prsltPrevious = new2(dbw_result, iColumns); nColsPrevious = iColumns; for (i = 0; i < iColumns; i++) { if (prslt[i].type == DBWT_Char) { prsltPrevious[i].pchCharValue = new2(char, prslt[i].iScale); } else { prsltPrevious[i].pchCharValue = 0; } } } for (i = 0; i < iColumns; i++) { prsltPrevious[i].iIsNull = prslt[i].iIsNull; if (prslt[i].iIsNull) continue; switch(prslt[i].type) { case DBWT_Char: strcpy(prsltPrevious[i].pchCharValue, prslt[i].pchCharValue); break; case DBWT_Float: prsltPrevious[i].fValue = prslt[i].fValue; break; case DBWT_Int: prsltPrevious[i].iIntValue = prslt[i].iIntValue; break; } }#ifdef _Windows FlushMessages();#endif iSequence++;}voidFormatHeadings( dbw_result *prslt, int iColumns){ prsltCurrent = prslt; iColsCurrent = iColumns; FormattedWrite(pchHeadings); prsltCurrent = 0; iColsCurrent = 0;}voidFormatErrors( long iErrNo, dbw_buf pchErrMsg, dbw_buf pchSQL){ iErrNoCurrent = iErrNo; pchErrMsgCurrent = pchErrMsg; pchSQLCurrent = pchSQL; FormattedWrite(pchError); iErrNoCurrent = 0; pchErrMsgCurrent = 0; pchSQLCurrent = 0;}char *CopyUnescaped(char *pchData){ char *pchTemp; char *pchOut; int iBytes; char c; for (pchTemp = pchData, iBytes = 0; *pchTemp; iBytes++, GetNextEscape(&pchTemp)); pchOut = new2(char, iBytes + 1); pchTemp = pchOut; while (*pchData) *pchTemp++ = GetNextEscape(&pchData); *pchTemp = 0; return pchOut;}voidReadVariables( int iContentLength, FILE *fp){ char *pchData; char *pchVar; char *pchVal; char *pchEnd; dbw_value *pval; pchData = new2(char, iContentLength + 1); fread(pchData, 1, iContentLength, fp); pchData[iContentLength] = 0; pchVar = pchData; while (*pchVar) { pchVal = pchVar; while (*pchVal != '=' && *pchVal != '&' && *pchVal) pchVal++; if (!*pchVal) break; if (*pchVal == '&') { pchVar = pchVal + 1; continue; } *pchVal++ = 0; pchEnd = pchVal; while (*pchEnd != '&' && *pchEnd) pchEnd++; if (*pchEnd) *pchEnd++ = 0; pchVal = CopyUnescaped(pchVal); pchVar = CopyUnescaped(pchVar); pval = new(dbw_value); pval->pchKey = pchVar; pval->pchValue = pchVal; pval->pvalNext = pvalForm; pvalForm = pval; pchVar = pchEnd; } free(pchData);}#ifdef _Windowsint CALLBACKWinMain(HINSTANCE hInstance, HINSTANCE hPrec, LPSTR lpCmdLine, int nShow)#elseintmain(int argc, char **argv)#endif{#ifdef _Windows static char pchServerProtocol[80], pchServerSoftware[256], pchPath[256], pchArgsBuf[1024], pchContentLength[80]; char *pchDataFile, *pchOutput, *pchContentFile, *pchArgs;#else char *pchServerProtocol, *pchServerSoftware, *pchContentLength, *pchArgs, *pchPath;#endif int i; int iArg; char *c, *c2;#ifdef _Windows pchDataFile = lpCmdLine; c = strchr(lpCmdLine, ' '); if (!c) return 1; *c++ = 0; pchContentFile = c; c = strchr(c, ' '); if (!c) return 1; *c++ = 0; pchOutput = c; c = strchr(c, ' '); if (c) *c = 0; pchArgs = pchArgsBuf; GetPrivateProfileString("CGI", "Request Protocol", "HTTP/1.0", pchServerProtocol, 80, pchDataFile); GetPrivateProfileString("CGI", "Server Software", "Unknown", pchServerSoftware, 256, pchDataFile); GetPrivateProfileString("CGI", "Query String", "", pchArgs, 256, pchDataFile); GetPrivateProfileString("CGI", "Physical Path", "", pchPath, 256, pchDataFile); GetPrivateProfileString("CGI", "Content Length", "", pchContentLength, 80, pchDataFile); if (*pchContentLength) { FILE *fp = fopen(pchContentFile, "rb"); ReadVariables(atoi(pchContentLength), fp); fclose(fp); } fpOutput = fopen(pchOutput, "wb"); iPid = (long) hInstance;#else fpOutput = stdout; pchServerProtocol = getenv("SERVER_PROTOCOL"); pchServerSoftware = getenv("SERVER_SOFTWARE"); pchContentLength = getenv("CONTENT_LENGTH"); pchPath = getenv("PATH_TRANSLATED"); pchArgs = getenv("QUERY_STRING"); if (pchContentLength) ReadVariables(atoi(pchContentLength), stdin); iPid = getpid();#endif fprintf(fpOutput, "%s 200 Document follows\r\n" "MIME-Version: 1.0\r\n" "Server: %s * dbcgi\r\n" "Content-Type: text/html\r\n\r\n", pchServerProtocol, pchServerSoftware); if (!pchArgs || !*pchArgs) { ppchArgList = 0; nArgs = 0; } else { nArgs = 1; for (c = pchArgs; *c; c++) if (*c == '+') nArgs++; ppchArgList = new2(char *, nArgs); c = pchArgs; iArg = 0; do { if (*c == '+' || !*c) { for (c2 = pchArgs, i = 0; c2 < c; i++) GetNextEscape(&c2); ppchArgList[iArg] = new2(char, i + 1); for (c2 = pchArgs, i = 0; c2 < c; i++) { ppchArgList[iArg][i] = GetNextEscape(&c2); } ppchArgList[iArg][i] = 0; iArg++; pchArgs = c2 + 1; } } while (*c++); } pchError = StringDuplicate("<H1>Error</H1>" "Error %n \"%e\" occurred in<BR>" "<STRONG>%c</STRONG><BR>" "---- End of error ----<BR>"); ReadFile(pchPath); return 0;}voidFreeString(char *pchData){ if (pchData) free(pchData);}voidPutEnvVar(char const *pchVariable, char const *pchValue){ if (pchVariable && pchValue) { char *pchBuffer; pchBuffer = new2(char, strlen(pchVariable) + strlen(pchValue) + 2); strcpy(pchBuffer, pchVariable); strcat(pchBuffer, "="); strcat(pchBuffer, pchValue); putenv(pchBuffer); /* Note that we must *not* free pchBuffer */ }}dbw_bindinfo *FindColInfo( dbw_typemap *atm, int iEntries, dbw_result *prslt, char const *pchColumn, int iColType, int iColumnWidth, int iColumnPrec){ static dbw_bindinfo bi; while (iEntries--) { if (atm->iOrigType == iColType) { bi.iBindType = atm->iBindType; prslt->type = atm->type; prslt->pchHeading = StringDuplicate(pchColumn); switch (atm->type) { case DBWT_Char: if (atm->iSize) bi.iWidth = atm->iSize; else bi.iWidth = iColumnWidth + 1; prslt->pchCharValue = new2(char, bi.iWidth); bi.pchData = prslt->pchCharValue; prslt->iScale = bi.iWidth - 1; break; case DBWT_Int: bi.iWidth = sizeof(long); bi.pchData = (char *) &prslt->iIntValue; prslt->iScale = 0; break; case DBWT_Dec: bi.iWidth = sizeof(long); bi.pchData = (char *) &prslt->iIntValue; prslt->iScale = iColumnPrec; break; case DBWT_Float: bi.iWidth = sizeof(double); bi.pchData = (char *) &prslt->fValue; prslt->iScale = iColumnPrec; break; case DBWT_Raw: if (atm->iSize) bi.iWidth = atm->iSize; else bi.iWidth = iColumnWidth; prslt->pchCharValue = new2(char, bi.iWidth); bi.pchData = prslt->pchCharValue; prslt->iScale = iColumnWidth; break; case DBWT_Raw_Sidx: if (atm->iSize) bi.iWidth = atm->iSize + sizeof(short); else bi.iWidth = iColumnWidth + sizeof(short); prslt->pchCharValue = new2(char, bi.iWidth); bi.pchData = prslt->pchCharValue; prslt->iScale = iColumnWidth; break; case DBWT_Raw_Lidx: if (atm->iSize) bi.iWidth = atm->iSize + sizeof(long); else bi.iWidth = iColumnWidth + sizeof(long); prslt->pchCharValue = new2(char, bi.iWidth); bi.pchData = prslt->pchCharValue; prslt->iScale = iColumnWidth; break; } return &bi; } atm++; } return 0;}char *GetValue( dbw_value *pval, char const *pchKey){ while (pval && !StringCompare(pval->pchKey, pchKey, 256)) pval = pval->pvalNext; if (pval) return StringDuplicate(pval->pchValue); return 0;}struct __dbw_conninfo *FindConnection(dbw_value *pval){ char *pchConnID = GetValue(pval, "ConnID"); dbw_connection *pconn; if (!pchConnID) { FormatErrors(0, "No connection ID specified", "Syntax"); return 0; } for (pconn = pconnList; pconn && strcmp(pconn->pchConnID, pchConnID); pconn = pconn->pconnNext); if (!pconn) FormatErrors(0, "No such connection", pchConnID); FreeString(pchConnID); return pconn ? pconn->pci : 0;}intAddConnection(dbw_value *pval, struct __dbw_conninfo *pinfo){ char *pchConnID = GetValue(pval, "ConnID"); dbw_connection *pconn = new(dbw_connection); if (!pchConnID) { FormatErrors(0, "No connection ID specified", "Syntax"); free(pconn); return 0; } pconn->pconnNext = pconnList; pconn->pci = pinfo; pconn->pchConnID = pchConnID; pconnList = pconn; return 1;}voidDropConnection(dbw_value *pval){ char *pchConnID = GetValue(pval, "ConnID"); dbw_connection **ppconn, *pconn; if (!pchConnID) { FormatErrors(0, "No connection ID specified", "Syntax"); return; } for (ppconn = &pconnList; *ppconn && strcmp((*ppconn)->pchConnID, pchConnID); ppconn = &(*ppconn)->pconnNext); if (*ppconn) { pconn = (*ppconn)->pconnNext; free((*ppconn)->pci); free((*ppconn)->pchConnID); free(*ppconn); *ppconn = pconn; } else { FormatErrors(0, "No such connection", pchConnID); } FreeString(pchConnID);}#ifdef _Windowsvoid FlushMessages(){ MSG msg; while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { TranslateMessage( &msg ); DispatchMessage( &msg ); }}#endif